#include "utils.h"
#include <SOIL2.h>
#include "root_dir.h"

std::string getResourcePath(const char* relpath)
{
    // std::string root = "D:/projects/glengine/resources/";
    std::string root = std::string(resource_root);
    return root + relpath;
}

void printShaderLog(GLuint shader)
{
    int len = 0;
    int chWritten = 0;
    char* log;
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
    if (len > 0)
    {
        log = (char*)malloc(len);
        glGetShaderInfoLog(shader, len, &chWritten, log);
        std::cout << "Shader Info Log: " << log << std::endl;
        free(log);
    }
}

void printProgramLog(GLuint program)
{
    int len = 0;
    int chWritten = 0;
    char* log;
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
    if (len > 0)
    {
        log = (char*)malloc(len);
        glGetProgramInfoLog(program, len, &chWritten, log);
        std::cout << "Program Info Log: " << log << std::endl;
        free(log);
    }
}

bool checkOpenGLError()
{
    bool foundError = false;
    int glErr = glGetError();
    while (glErr != GL_NO_ERROR)
    {
        std::cout << "glError: " << glErr << std::endl;
        foundError = true;
        glErr = glGetError();
    }
    return foundError;
}

std::string readShaderSource(const std::string& filePath)
{
    std::string content;
    std::ifstream s(filePath, std::ios::in);
    std::string line;
    while (!s.eof())
    {
        std::getline(s, line);
        content.append(line + "\n");
    }
    s.close();
    return content;
}

GLuint createShaderProgram(const std::string& vertexPath, const std::string& fragmentPath)
{
    GLint vertCompiled;
    GLint fragCompiled;
    GLint linked;

    std::string vshaderstr = readShaderSource(vertexPath.c_str());
    std::string fshaderstr = readShaderSource(fragmentPath.c_str());
    const char* vshaderSource = vshaderstr.c_str();
    const char* fshaderSource = fshaderstr.c_str();

    GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
    GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(vShader, 1, &vshaderSource, NULL);
    glShaderSource(fShader, 1, &fshaderSource, NULL);
    glCompileShader(vShader);
    checkOpenGLError();
    glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertCompiled);
    if (vertCompiled != 1)
    {
        std::cout << "vertex shader compilation failed" << std::endl;
        printShaderLog(vShader);
    }
    glCompileShader(fShader);
    checkOpenGLError();
    glGetShaderiv(fShader, GL_COMPILE_STATUS, &fragCompiled);
    if (fragCompiled != 1)
    {
        std::cout << "fragment shader compilation failed" << std::endl;
        printShaderLog(fShader);
    }
    GLuint vfProgram = glCreateProgram();
    glAttachShader(vfProgram, vShader);
    glAttachShader(vfProgram, fShader);
    glLinkProgram(vfProgram);
    checkOpenGLError();
    glGetProgramiv(vfProgram, GL_LINK_STATUS, &linked);
    if (linked != 1)
    {
        std::cout << "link failed\n";
        printProgramLog(vfProgram);
    }
    return vfProgram;
}

GLuint loadTexture(const char* texturePath)
{
    GLuint textureID;
    textureID = SOIL_load_OGL_texture(texturePath,
        SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
    if (textureID == 0)
        std::cout << "could not find texture file" << texturePath << std::endl;
    return textureID;
}

